How to embed/require a javascript only once in Raz...
# help-with-other
t
This is probably an asp.net mvc question. I have razor partial templates for blocks in my blocklist in Umbraco. Multiple of these blocks can be rendered in the same page. I need to use an external javascript file when these are displayed on the page, but only then, and only one. Preferably I'd like to also control if the script tag ends up in
head
or
body
. Is this possible to control with razor templates?
s
You can set a value in Context.Items to "remember" that the script has already been added. For example
Copy code
@if (Context.Items.ContainsKey("HasAddedThisBlocksScript") == false) {
    @Context.Items.TryAdd("HasAddedThisBlocksScript", true);
    <script>
        alert("just once please!");
    </script>
}
t
The future truly is here already today, thank you @skttl I guess Razor MVC doesn't have any built in "head" handler?
Some form of "slot" solution would be useful. Like define an area in the main layout that you can populate from deeper templates.
m
taking this and running with it to add an HtmlExtension..
@Html.RenderPartialViewCss()
in the template head/foot wherever
Html.RequiresPartialCss("~/css/owner/slickslider.css");
in the partial etc.. https://cdn.discordapp.com/attachments/1343564908192600084/1343569193034977391/message.txt?ex=67bdbfd1&is=67bc6e51&hm=d82353955a708450598ad9028e61df20e56e79311d0ace991873029398d2d73e&
you can do that with templates (aka views) `@section head {}`// but not with partials/view components as there is no guarantee what order in the lifecycle partials inject themselves
t
Above looks like a great solution as well, thank you. What do you mean with @section head btw? Is that another form of templating syntax?
m
in a template (view) NOT PARTIAL.. you can have
@RenderSection("bodyEnd", false)
and then in the nested (inheriting) template you have
@section bodyEnd { <script>...</script>}
for injecting/overriding that section
t
ah gotcha!
j
> Preferably I'd like to also control if the script tag ends up in head or body. These days it's always best to include JS in the head and use the
defer
attribute. The browser will download, parse, and compile the JS file asynchronously for maximum efficiency then actually execute once HTML is parsed (as if it was inlcuded at the end of the body). If you're using modern JS in a module (
<script src="somefile.js" type="module"></script>
) then it will defer anyway. It will also just load once, however many times you include it in the page - so you can just spam it inline if you like.
d
Thanks @Jason, I always learn something new going through these posts
s
@Jason thanks, we are used to preloading scripts in head, and then placing them just before . But I can see that, just loading them with defer as soon as possible is probably better 🙂
j
The difference in speed between preloading like that and defer is tiny, if it's even measuable for a given site, but it's a simpler/nicer API to achieve the same result.
s
Agreed - I went and changed our baseline build too 🙂
j
Tangentially related to the question... I prefer to avoid doing this kind of thing at all and handle all my frontend dependencies in the frontend itself - dynamically loading where appropriate.
Copy code
js
if(condition) { import("some/js-file.js"); }
l
What I do is create es modules for the scripts that go in a block. Then I use . This means that there could be multiple script tags pointing to the same source, but because it's a module, it will wait for the DOM to load and load the actual file only once.
I do this mostly for view components that are in a package and you have no control of the rest of the HTML output and views of the consuming Umbraco project.
4 Views